我看本節目乾脆改名為《iOS Developer Learning ListView》算了
iOS要做多選列表有兩種方式
左邊由tableView來幫我們管理狀態
只要.allowsMultipleSelectionDuringEditing = true
最後從indexPathsForSelectedRows取得結果即可
而右邊則是用陣列記住每個選項是否選取
然後設定cell.accessoryType = .checkmark
Flutter這邊使用CheckboxListTile來完成多選功能
由於它是StatelessWidget
不像昨天提到的ExpansionTile會自己管理狀態
因此也必須用陣列儲存資料☘️☘️☘️
然後用setState去刷新畫面
onChanged: (check) {
setState(() {
checkList[idx] = check;
});
},
接著介紹一下CheckboxListTile一些特別的屬性
使用Flutter Favorite program裡面的flutter_slidable
(根本就是Flutter界的SwipeCellKit XD)☘️☘️☘️
看最上面的gif
可以發現我有特別放慢動作
再加上我精心的說明
應該很清楚四種動畫效果的差別了(哈哈)
無key不能刪
//這樣才可以
Slidable(
key: Key(slidableItem.title)
list不能放不同型別
//本來想說把Widget塞進models裡面就好XD
不在list不能刪
//我原本是寫成這樣, 用數量去當作state
//1.
int showItemCount = slidableItems.length + 1;
//2.
onDismissed: (type) {
setState(() {
showItemCount = slidableItems.length;
});
},
//3.
return ListView.builder(
itemCount: showItemCount,
itemBuilder: (ctx, idx) {
if (idx == slidableItems.length) {
return dismissalItem;
} else {
return _createSlidableListTile(idx);
}
}
);
//但後來乖乖寫成這樣才行
//1.
onDismissed: (type) {
setState(() {
slidableItems.removeLast();
});
},
//2.
return ListView.builder(
itemCount: slidableItems.length,
itemBuilder: (ctx, idx) {
if (slidableItems[idx].canDelete) {
return _createSlidableDismissalListTile(idx);
} else {
return _createSlidableListTile(idx);
}
}
);
在Flutter裡已經沒有吐司可以吃了XD
取得代之建議的是使用這玩意
它是寄生在Scaffold之中
所以必須先取得Scaffold
像這樣`Scaffold.of(context).showSnackBar(SnackBar(content: Text(tapInfo)));
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
enum SliableType{
archive,
share,
more,
delete,
}
class SliableItem{
final String title;
final String subTitle;
final Widget actionPane;
final bool canDelete;
SliableItem(this.title, this.subTitle, this.actionPane, this.canDelete);
}
class LessonPageListViewSwipe extends StatefulWidget {
@override
_LessonPageListViewSwipeState createState() => _LessonPageListViewSwipeState();
}
class _LessonPageListViewSwipeState extends State<LessonPageListViewSwipe> {
List slidableItems = [
SliableItem("Behind效果", "Action像在Tile的背面\n(最靠外面的Action最先出現)",
SlidableBehindActionPane(), false),
SliableItem("Scroll效果", "Action像在Tile的兩側\n(最靠中間的Action最先出現)",
SlidableScrollActionPane(), false),
SliableItem("Strech效果", "Action像在Tile的兩側\n(Action同時出現, 沒有重疊的感覺)",
SlidableStrechActionPane(), false),
SliableItem("Drawer效果", "Action像在Tile的兩側\n(Action同時出現, 會有重疊的感覺)",
SlidableDrawerActionPane(), false),
SliableItem("送我一程吧~~~~", "", SlidableStrechActionPane(), true),
];
@override
Widget build(BuildContext context) {
void _showSnackBar(SliableType actionType, int index) {
final tapInfo = "$index is ${actionType.toString()}";
print(tapInfo);
Scaffold.of(context).showSnackBar(SnackBar(content: Text(tapInfo),));
}
Widget _createSlidableListTile(int index) {
//都用SlideAction
final leftActionMenu = [
SlideAction(
child: FlutterLogo(),
color: Colors.yellow,
onTap: () => _showSnackBar(SliableType.archive, index),
),
SlideAction(
child: Text("tap me", textAlign: TextAlign.center),
color: Colors.greenAccent,
onTap: () => _showSnackBar(SliableType.share, index),
)
];
//都用IconSlideAction
final rightActionMenu = [
//無字
IconSlideAction(
color: Colors.black45,
icon: Icons.more_horiz,
onTap: () => _showSnackBar(SliableType.more, index),
),
//有字
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () => _showSnackBar(SliableType.delete, index),
)
];
final slidableItem = slidableItems[index];
return Slidable(
actions: leftActionMenu,
secondaryActions: rightActionMenu,
actionPane: slidableItem.actionPane,
actionExtentRatio: 0.1 * (index + 1),
child: Container(
color: Colors.white,
child: ListTile(
title: Text(slidableItem.title),
subtitle: Text(slidableItem.subTitle),
isThreeLine: true,
leading: CircleAvatar(
child: Text('$index'),
foregroundColor: Colors.white,
backgroundColor: Colors.orange,
),
),
),
);
}
Widget _createSlidableDismissalListTile(int index) {
final slidableItem = slidableItems[index];
return Slidable(
key: Key(slidableItem.title),
actionPane: slidableItem.actionPane,
actionExtentRatio: 0.25,
child: Container(
color: Colors.white,
child: ListTile(
title: Text(slidableItem.title,
style: TextStyle(color: Colors.redAccent),
),
),
),
secondaryActions: [
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
)
],
dismissal: SlidableDismissal(
child: SlidableDrawerDismissal(),
dismissThresholds: {SlideActionType.secondary: 0.3},
onDismissed: (type) {
setState(() {
slidableItems.removeLast();
});
},
),
);
}
return ListView.builder(
itemCount: slidableItems.length,
itemBuilder: (ctx, idx) {
if (slidableItems[idx].canDelete) {
return _createSlidableDismissalListTile(idx);
} else {
return _createSlidableListTile(idx);
}
}
);
}
}
下集預告:網格(總算不是列表了)